﻿//******************************************************************************************************
//  TestBench.cs - Gbtc
//
//  Copyright © 2010, Grid Protection Alliance.  All Rights Reserved.
//
//  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
//  the NOTICE file distributed with this work for additional information regarding copyright ownership.
//  The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
//  not use this file except in compliance with the License. You may obtain a copy of the License at:
//
//      http://www.opensource.org/licenses/eclipse-1.0.php
//
//  Unless agreed to in writing, the subject software distributed under the License is distributed on an
//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
//  License for the specific language governing permissions and limitations.
//
//  Code Modification History:
//  ----------------------------------------------------------------------------------------------------
//  07/08/2010 - Stephen C. Wills
//       Generated original version of source code.
//
//******************************************************************************************************

using System;
using System.Collections.Generic;
using TestBenchApi.Package;
using TVA;

namespace TestBenchApi
{
    /// <summary>
    /// Represents a test bench used to run tests on a concentrator.
    /// </summary>
    public class TestBench
    {

        #region [ Members ]

        // Events

        /// <summary>
        /// Triggered when the <see cref="TestBench"/> needs to display an error message to the user without failing.
        /// </summary>
        public event EventHandler<EventArgs<string>> DisplayErrorMessage;

        /// <summary>
        /// Triggered when the <see cref="TestBench"/> is started.
        /// </summary>
        public event EventHandler TestBenchStarted;

        /// <summary>
        /// Triggered when the <see cref="TestBench"/> is stopped.
        /// </summary>
        public event EventHandler TestBenchStopped;

        // Fields

        private ICollection<Generator> m_generators;
        private Receiver m_receiver;
        private bool m_running;

        #endregion

        #region [ Constructors ]

        /// <summary>
        /// Creates a new instance of the <see cref="TestBench"/> class.
        /// </summary>
        public TestBench()
        {
            m_generators = new List<Generator>();
            m_receiver = new Receiver();
            m_receiver.DisplayErrorMessage += m_receiver_DisplayErrorMessage;
        }

        /// <summary>
        /// Creates and initializes a new instance of the <see cref="TestBench"/> class.
        /// </summary>
        /// <param name="packageFile">The package file containing settings to initialize the test bench.</param>
        public TestBench(PackageFile packageFile)
            : this()
        {
            Initialize(packageFile);
        }

        #endregion

        #region [ Properties ]

        /// <summary>
        /// Determines whether the <see cref="TestBench"/> is currently running or not.
        /// </summary>
        public bool Running
        {
            get
            {
                return m_running;
            }
        }

        #endregion

        #region [ Methods ]

        /// <summary>
        /// Initializes the <see cref="TestBench"/>.
        /// </summary>
        /// <param name="packageFile">The package file containing settings used to initialize the test bench.</param>
        public void Initialize(PackageFile packageFile)
        {
            InitializeGenerators(packageFile);
            InitializeReceiver(packageFile);
        }

        /// <summary>
        /// Starts the <see cref="TestBench"/>.
        /// </summary>
        public void Start()
        {
            m_receiver.Start();
            foreach (Generator generator in m_generators)
                generator.Start();

            OnTestBenchStarted();
        }

        /// <summary>
        /// Stops the <see cref="TestBench"/>.
        /// </summary>
        public void Stop()
        {
            foreach (Generator generator in m_generators)
                generator.Stop();

            m_receiver.Stop();
            OnTestBenchStopped();
        }

        // Initialize the generators using the generator entries in the package file.
        private void InitializeGenerators(PackageFile packageFile)
        {
            GeneratorGroupEntry generatorGroup = packageFile.GeneratorGroup;
            ConcentratorEntry concentrator = packageFile.Concentrator;
            Dictionary<string, string> generatorSettings = new Dictionary<string, string>(generatorGroup.Settings);

            m_generators.Clear();

            // Remove unnecessary settings.
            generatorSettings.Remove("numberOfGenerators");
            generatorSettings.Remove("startPort");

            // Add a setting for the concentrator's host name.
            generatorSettings.Add("concentratorHostName", concentrator.HostName);

            for (int i = 0; i < generatorGroup.NumberOfGenerators; i++)
            {
                // Set the setting for the port used by the generator.
                generatorSettings["port"] = (generatorGroup.StartPort + i).ToString();

                // Initialize the generator and add it to the collection.
                Generator generator = new Generator();
                generator.Initialize(generatorSettings);
                m_generators.Add(generator);
            }
        }

        // Initialize the generators using the receiver entry in the package file.
        private void InitializeReceiver(PackageFile packageFile)
        {
            ReceiverEntry receiver = packageFile.Receiver;
            ConcentratorEntry concentrator = packageFile.Concentrator;
            Dictionary<string, string> settings = new Dictionary<string, string>(receiver.Settings);

            // Add settings for the concentrator's host name and access ID.
            settings.Add("concentratorHostName", concentrator.HostName);
            settings.Add("concentratorAccessId", concentrator.AccessId.ToString());

            m_receiver.Initialize(settings);
        }

        /// <summary>
        /// Raises the <see cref="DisplayErrorMessage"/> event.
        /// </summary>
        /// <param name="errorMessage">The error message to be displayed.</param>
        protected virtual void OnDisplayErrorMessage(string errorMessage)
        {
            if (DisplayErrorMessage != null)
                DisplayErrorMessage(this, new EventArgs<string>(errorMessage));
        }

        /// <summary>
        /// Raises the <see cref="TestBenchStarted"/> event.
        /// </summary>
        protected virtual void OnTestBenchStarted()
        {
            m_running = true;

            if (TestBenchStarted != null)
                TestBenchStarted(this, EventArgs.Empty);
        }

        /// <summary>
        /// Raises the <see cref="TestBenchStopped"/> event.
        /// </summary>
        protected virtual void OnTestBenchStopped()
        {
            m_running = false;

            if (TestBenchStopped != null)
                TestBenchStopped(this, EventArgs.Empty);
        }

        // Forwards the receiver's error messages through the DisplayErrorMessage event.
        private void m_receiver_DisplayErrorMessage(object sender, EventArgs<string> e)
        {
            OnDisplayErrorMessage(e.Argument);
        }

        #endregion

        #region [ Operators ]

        #endregion

        #region [ Static ]

        // Static Fields

        // Static Constructor

        // Static Properties

        // Static Methods

        #endregion
        
    }
}
